﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Web;
using System.Xml.Linq;
using Maple.Weixin.MP.Cryptography;
using Maple.Weixin.MP.Entities;
using Maple.Weixin.MP.Entities.JsonResult;
using Maple.Weixin.MP.Entities.Menus;
using Maple.Weixin.MP.Entities.Messages;
using Maple.Weixin.MP.OAuth;
using Maple.Weixin.MP.QRCode;

namespace Maple.Weixin.MP
{
    /// <summary>
    /// 微信服务。
    /// </summary>
    public interface IWeixinService
    {
        /// <summary>
        /// 检验消息的真实性，并且获取解密后的明文。
        /// </summary>
        /// <param name="signature">签名，对应URL中的msg_signature。</param>
        /// <param name="timestamp">时间戳，对应URL中的timestamp。</param>
        /// <param name="nonce">随机串，对应URL中的nonce。</param>
        /// <param name="postData">密文，对应POST的数据。</param>
        /// <param name="message">解密后的原文，当return返回0时有效。</param>
        /// <returns>解密成功返回0，否则为错误码。</returns>
        WXBizMsgCryptErrorCode DecryptMessage(string signature, string timestamp, string nonce, string postData,
            ref string message);

        /// <summary>
        /// 将回复用户的消息加密打包。
        /// </summary>
        /// <param name="replyMessage">回复用户的消息，XML格式的字符串。</param>
        /// <param name="timestamp">时间戳。</param>
        /// <param name="nonce">随机串，可以自己生成，也可以用URL中的nonce。</param>
        /// <param name="encryptMessage">加密后的密文。包括msg_signature, timestamp, nonce, encrypt的XML格式字符串。</param>
        /// <returns>成功返回0，否则返回错误码。</returns>
        WXBizMsgCryptErrorCode EncryptMessage(string replyMessage, string timestamp, string nonce,
            ref string encryptMessage);

        /// <summary>
        /// 获取内部的AccessToken容器。
        /// </summary>
        IAccessTokenContainer AccessTokenContainer { get; }

        /// <summary>
        /// 获取微信签名。用于首次验证。
        /// </summary>
        /// <param name="timestamp">时间戳。</param>
        /// <param name="nonce">随机数。</param>
        /// <returns>根据参数计算的签名。</returns>
        string GetSignature(string timestamp, string nonce);

        /// <summary>
        /// 获取access_token。
        /// </summary>
        /// <returns>获取到的access_token。</returns>
        string GetAccessToken(bool getNewToken = false);

        /// <summary>
        /// 创建OAuth认证的起始Url。
        /// </summary>
        /// <param name="redirectUrl">请求之后的回调地址。</param>
        /// <param name="state">重定向之后的原样返回参数，必须为a-zA-Z0-9。</param>
        /// <param name="scope">范围的枚举值。</param>
        /// <returns>对应请求的Url地址。</returns>
        string CreateAuthorizeUrl(string redirectUrl, string state, OAuthScope scope);

        /// <summary>
        /// 创建OAuth认证的起始Url。
        /// </summary>
        /// <param name="appid">公众号的APPID。</param>
        /// <param name="redirectUrl">请求之后的回调地址。</param>
        /// <param name="state">重定向之后的原样返回参数，必须为a-zA-Z0-9。</param>
        /// <param name="scope">范围的枚举值。</param>
        /// <returns>对应请求的Url地址。</returns>
        string CreateAuthorizeUrl(string appid, string redirectUrl, string state, OAuthScope scope);

        /// <summary>
        /// 使用code获取OAuth认证的AccessToken。如果使用的是snsapi_base，那到这里就可以拿到openid了。
        /// </summary>
        /// <param name="code">请求到的code值。</param>
        /// <returns>取得的AccessToken结果。</returns>
        OAuthAccessTokenResult GetOAuthAccessToken(string code);

        /// <summary>
        /// 使用code获取OAuth认证的AccessToken。如果使用的是snsapi_base，那到这里就可以拿到openid了。
        /// </summary>
        /// <param name="appid">公众号的APPID。</param>
        /// <param name="secret">公众号的APPSECRET。</param>
        /// <param name="code">请求到的code值。</param>
        /// <returns>取得的AccessToken结果。</returns>
        OAuthAccessTokenResult GetOAuthAccessToken(string appid, string secret, string code);

        /// <summary>
        /// 刷新AccessToken。
        /// </summary>
        /// <returns>取得的AccessToken结果。</returns>
        OAuthAccessTokenResult RefreshAccessToken(string refreshToken);

        /// <summary>
        /// 刷新AccessToken。
        /// </summary>
        /// <param name="appid">公众号的APPID。</param>
        /// <param name="refreshToken">得到的refreshToken参数。</param>
        /// <returns>取得的AccessToken结果。</returns>
        OAuthAccessTokenResult RefreshAccessToken(string appid, string refreshToken);

        /// <summary>
        /// 根据openid获取用户信息。
        /// </summary>
        /// <param name="accessToken">授权接口调用凭证。</param>
        /// <param name="openid">用户唯一标识。</param>
        /// <param name="lang">语言，目前支持简体（zh-CN）、繁体（zh-TW）、英语（en）。</param>
        /// <returns>用户信息的结果。</returns>
        UserInfoResult GetUserInfoByOpenId(string accessToken, string openid, string lang = "zh-CN");

        /// <summary>
        /// 检测授权的accessToken是否有效。
        /// </summary>
        /// <param name="accessToken">给定的AccessToken。</param>
        /// <param name="openid">用户唯一标识。</param>
        /// <returns>微信返回结果。</returns>
        WeixinServiceResult IsValidAccessToken(string accessToken, string openid);

        /// <summary>
        /// 创建二维码Ticket。
        /// </summary>
        /// <param name="type">二维码类型，永久还是临时。</param>
        /// <param name="expireSeconds">过期时间，如果是永久此值无效。</param>
        /// <param name="sceneid">场景值ID。</param>
        /// <returns>二维码的ticket。</returns>
        QRCodeTicketResult CreateQRCodeTicket(QRCodeType type, int expireSeconds, Int32 sceneid);

        /// <summary>
        /// 创建二维码Ticket。
        /// </summary>
        /// <param name="accessToken">给定的AccessToken。</param>
        /// <param name="type">二维码类型，永久还是临时。</param>
        /// <param name="expireSeconds">过期时间，如果是永久此值无效。</param>
        /// <param name="sceneid">场景值ID。</param>
        /// <returns>二维码的ticket。</returns>
        QRCodeTicketResult CreateQRCodeTicket(string accessToken, QRCodeType type, int expireSeconds, Int32 sceneid);

        /// <summary>
        /// 根据Ticket获取二维码。
        /// </summary>
        /// <param name="ticket">获取二维码的Ticket。</param>
        /// <returns>二维码的路径。</returns>
        string GetQRCode(string ticket);

        /// <summary>
        /// 处理请求消息。
        /// </summary>
        /// <param name="request">微信端发送来的Http请求。</param>
        /// <returns>响应的消息。</returns>
        ResponseMessageBase HandleMessage(HttpRequestBase request);

        /// <summary>
        /// 处理请求消息。
        /// </summary>
        /// <param name="inputStream">请求消息的流。</param>
        /// <returns>响应的消息。</returns>
        ResponseMessageBase HandleMessage(Stream inputStream);

        /// <summary>
        /// 处理请求消息。
        /// </summary>
        /// <param name="document">请求消息的XML文档。</param>
        /// <param name="encrypt">是否以加密模式请求。</param>
        /// <returns>响应的消息。</returns>
        ResponseMessageBase HandleMessage(XDocument document, bool encrypt = false);

        /// <summary>
        /// 根据指定的Button创建菜单。
        /// </summary>
        /// <param name="button">创建菜单对应的Button。</param>
        /// <returns>微信服务的结果。</returns>
        WeixinServiceResult CreateMenu(Button button);

        /// <summary>
        /// 根据指定的Button创建菜单。
        /// </summary>
        /// <param name="accessToken">给定的AccessToken。</param>
        /// <param name="button">创建菜单对应的Button。</param>
        /// <returns>微信服务的结果。</returns>
        WeixinServiceResult CreateMenu(string accessToken, Button button);

        /// <summary>
        /// 发送模板消息。
        /// </summary>
        /// <param name="openid">发送对象的openid。</param>
        /// <param name="templateid">发送消息的模板id。</param>
        /// <param name="url">点击模板消息之后的链接。</param>
        /// <param name="topColor">模板消息顶端的颜色。</param>
        /// <param name="data">模板消息所需的数据。</param>
        /// <returns>微信服务的结果。</returns>
        TemplateMessageResult SendTemplateMessage(string openid, string templateid, string url, string topColor,
            IDictionary<string, TemplateMessageData> data);

        /// <summary>
        /// 发送模板消息。
        /// </summary>
        /// <param name="accessToken">给定的AccessToken。</param>
        /// <param name="openid">发送对象的openid。</param>
        /// <param name="templateid">发送消息的模板id。</param>
        /// <param name="url">点击模板消息之后的链接。</param>
        /// <param name="topColor">模板消息顶端的颜色。</param>
        /// <param name="data">模板消息所需的数据。</param>
        /// <returns>微信服务的结果。</returns>
        TemplateMessageResult SendTemplateMessage(string accessToken, string openid, string templateid, string url,
            string topColor, IDictionary<string, TemplateMessageData> data);
    }
}
